home *** CD-ROM | disk | FTP | other *** search
/ Total Network Tools 2002 / NextStepPublishing-TotalNetworkTools2002-Win95.iso / Archive / Offline Browsing / HTTrack.exe / data1.cab / Sources / src / htsftp.c < prev    next >
Encoding:
C/C++ Source or Header  |  2001-04-28  |  28.9 KB  |  1,033 lines

  1. /* ------------------------------------------------------------ */
  2. /*
  3. HTTrack Website Copier, Offline Browser for Windows and Unix
  4. Copyright (C) Xavier Roche and other contributors
  5.  
  6. This program is free software; you can redistribute it and/or
  7. modify it under the terms of the GNU General Public License
  8. as published by the Free Software Foundation; either version 2
  9. of the License, or any later version.
  10.  
  11. This program is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with this program; if not, write to the Free Software
  18. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  19.  
  20.  
  21. Important notes:
  22.  
  23. - We hereby ask people using this source NOT to use it in purpose of grabbing
  24. emails addresses, or collecting any other private information on persons.
  25. This would disgrace our work, and spoil the many hours we spent on it.
  26.  
  27.  
  28. Please visit our Website: http://www.httrack.com
  29. */
  30.  
  31.  
  32. /* ------------------------------------------------------------ */
  33. /* File: basic FTP protocol manager                             */
  34. /* Author: Xavier Roche                                         */
  35. /* ------------------------------------------------------------ */
  36.  
  37. // Gestion protocole ftp
  38. // Version .05 (01/2000)
  39.  
  40. #include "htsftp.h"
  41.  
  42. #include "htsglobal.h"
  43. #include "htsbase.h"
  44. #include "htsnet.h"
  45. #include "htsthread.h"
  46. #include <stdio.h>
  47. #include <stdlib.h>
  48. #include <string.h>
  49. #if HTS_WIN
  50. #else
  51. //inet_ntoa
  52. #include <arpa/inet.h>
  53. #endif
  54.  
  55. #if HTS_WIN
  56. #ifndef __cplusplus
  57. // DOS
  58. #include <process.h>    /* _beginthread, _endthread */
  59. #endif
  60. #endif
  61.  
  62. // ftp mode passif
  63. #define FTP_PASV 1
  64.  
  65. #define FTP_DEBUG 0
  66. //#define FORK_DEBUG 0
  67.  
  68. #define FTP_STATUS_READY 1001
  69.  
  70. #if USE_BEGINTHREAD
  71. /*
  72. #ifdef __cplusplus
  73. // C++ -> Shell
  74. UINT back_launch_ftp( LPVOID pP ) {
  75.   lien_back* back=(lien_back*) pP;
  76.   if (back == NULL) {
  77.     //back->status=FTP_STATUS_READY;    // fini
  78.     //back->r.statuscode=-1;
  79.     return -1;
  80.   }
  81.   
  82.   // lancer ftp
  83.   run_launch_ftp(back);
  84.   // prΩt
  85.   back->status=0;
  86.  
  87.   return 0;    // thread completed successfully
  88. }
  89. #else
  90. */
  91. PTHREAD_TYPE back_launch_ftp( void* pP ) {
  92.   lien_back* back=(lien_back*) pP;
  93.   if (back == NULL) {
  94.     //back->status=FTP_STATUS_READY;    // fini
  95.     //back->r.statuscode=-1;
  96. #if FTP_DEBUG
  97.     printf("[ftp error: no args]\n");
  98. #endif
  99.     return PTHREAD_RETURN;
  100.   }
  101.   
  102.   // lancer ftp
  103. #if FTP_DEBUG
  104.   printf("[Launching main ftp routine]\n");
  105. #endif
  106.   run_launch_ftp(back);
  107.   // prΩt
  108.   back->status=0;
  109.   
  110.   return PTHREAD_RETURN;
  111. }
  112. /*#endif*/
  113. // lancer en back
  114. void launch_ftp(lien_back* back) {
  115. /*
  116. #ifdef __cplusplus
  117.   // C++ -> Shell
  118.   AfxBeginThread(back_launch_ftp,(LPVOID) back);
  119. #else
  120. */
  121.   // DOS
  122. #if FTP_DEBUG
  123.   printf("[Launching main ftp thread]\n");
  124. #endif
  125.   _beginthread(back_launch_ftp, 0, (void*) back);
  126. /*#endif*/
  127. }
  128.  
  129. #else
  130. // Unix sans pthread
  131. int back_launch_ftp(lien_back* back) {
  132.   // lancer ftp
  133.   run_launch_ftp(back);
  134.   // prΩt
  135.   back->status=0;
  136.   return 0;
  137. }
  138. void launch_ftp(lien_back* back,char* path,char* exec) {
  139.   FILE* fp = fopen(fconv(path),"wb");
  140.   if (fp) {
  141.     char _args[8][256];
  142.     char *args[8];
  143.     fclose(fp); fp=NULL;
  144.     
  145.     strcpy(_args[0],exec);
  146.     strcpy(_args[1],"-#R");
  147.     strcpy(_args[2],back->url_adr);
  148.     strcpy(_args[3],back->url_fil);
  149.     strcpy(_args[4],back->url_sav);
  150.     strcpy(_args[5],path);
  151.     //strcpy(_args[6],"");
  152.     args[0]=_args[0];
  153.     args[1]=_args[1];
  154.     args[2]=_args[2];
  155.     args[3]=_args[3];
  156.     args[4]=_args[4];
  157.     args[5]=_args[5];
  158.     args[6]=NULL;
  159.     switch (fork()) {    // note: vfork dΘconne un max'
  160.     case -1: printf("Can not vfork() process\n"); break;
  161.     case 0: 
  162.       if (execvp(args[0],args)==-1) {
  163.         fp=fopen(fconv(path),"wb");
  164.         if (fp) {
  165.           fprintf(fp,"-1 unable to launch %s",args[0]);
  166.           fclose(fp); fp=NULL;
  167.           rename(path,concat(path,".ok"));
  168.         } else remove(path);
  169.       }
  170.       _exit(0);    // exit 'propre'
  171.       break;
  172.     default:  // parent
  173.       // bah on fait rien..
  174.       break;         
  175.     }
  176.   }
  177. }
  178. #endif
  179.  
  180. // pour l'arrΩt du ftp
  181. #ifdef _WIN32
  182. #define _T_SOC_close(soc)  closesocket(soc); soc=INVALID_SOCKET;
  183. #else
  184. #define _T_SOC_close(soc)  close(soc); soc=INVALID_SOCKET;
  185. #endif
  186. #define _HALT_FTP { \
  187.   if ( soc_ctl     != INVALID_SOCKET ) _T_SOC_close(soc_ctl); \
  188.   if ( soc_servdat != INVALID_SOCKET ) _T_SOC_close(soc_servdat); \
  189.   if ( soc_dat     != INVALID_SOCKET ) _T_SOC_close(soc_dat); \
  190. }
  191. #define _CHECK_HALT_FTP \
  192.   if (stop_ftp(back)) { \
  193.   _HALT_FTP \
  194.   return 0; \
  195.   }
  196.  
  197. // la vΘritable fonction une fois lancΘes les routines thread/fork
  198. int run_launch_ftp(lien_back* back) {
  199.   char user[256]="anonymous";
  200.   char pass[256]="user@";
  201.   char line_retr[2048];
  202.   int port=21;
  203.   int port_pasv=0;
  204.   char adr_ip[1024];
  205.   char *adr,*real_adr;
  206.   char* ftp_filename="";
  207.   int timeout = 300;    // timeout
  208.   int timeout_onfly=8;  // attente rΘponse supplΘmentaire
  209.   int transfer_list=0;  // directory
  210.   int rest_understood=0;  // rest command understood
  211.   //
  212.   T_SOC soc_ctl=INVALID_SOCKET;
  213.   T_SOC soc_servdat=INVALID_SOCKET;
  214.   T_SOC soc_dat=INVALID_SOCKET;
  215.   //
  216.   line_retr[0]=adr_ip[0]='\0';
  217.   
  218.   timeout=300;
  219.   
  220.   // effacer
  221.   strcpy(back->r.msg,"");
  222.   back->r.statuscode=0;
  223.   back->r.size=0;
  224.   
  225.   // rΘcupΘrer user et pass si prΘsents, et sauter user:id@ dans adr
  226.   real_adr = strchr(back->url_adr,':');
  227.   if (real_adr) real_adr++;
  228.   else real_adr=back->url_adr;
  229.   while(*real_adr=='/') real_adr++;    // sauter /
  230.   if ( (adr = jump_identification(real_adr)) != real_adr) {  // user
  231.     int i=-1;
  232.     pass[0]='\0';
  233.     do {
  234.       i++;
  235.       user[i]=real_adr[i];
  236.     } while( (real_adr[i]!=':') && (real_adr[i]) );
  237.     user[i]='\0';
  238.     if (real_adr[i]==':') {    // pass
  239.       int j=-1;
  240.       i++;  // oui on saute aussi le :
  241.       do {
  242.         j++;
  243.         pass[j]=real_adr[i+j];
  244.       } while( ((int) (&real_adr[i+j+1]) < (int) adr) && (real_adr[i+j]) );
  245.       pass[j]='\0';
  246.     }
  247.   }
  248.   
  249.   // Calculer RETR <nom>
  250.   {
  251.     char* a;
  252.     a=back->url_fil + strlen(back->url_fil)-1;
  253.     while( ((int) a > (int) back->url_fil) && (*a!='/')) a--;
  254.     if (*a == '/') {    // ok repΘrΘ
  255.       a++;    // sauter /
  256.       ftp_filename=a;
  257.       if (strnotempty(a))
  258.         sprintf(line_retr,"RETR %s",a);
  259.       else {
  260.         transfer_list=1;
  261.         sprintf(line_retr,"LIST -A");
  262.       }
  263.     } else {
  264.       strcpy(back->r.msg,"Unexpected PORT error");
  265.       back->status=FTP_STATUS_READY;    // fini
  266.       back->r.statuscode=-1;
  267.     }
  268.   }
  269.   
  270. #if FTP_DEBUG
  271.   printf("Connecting to %s...\n",adr);
  272. #endif
  273.   
  274.   // connexion
  275.   {
  276.     struct sockaddr_in server;
  277.     t_hostent* hp;    
  278.     char * a;
  279.     char _adr[256];
  280.     _adr[0]='\0';
  281.     //T_SOC soc_ctl;
  282.     // effacer structure
  283.     bzero((char *)&server, sizeof(server));
  284.     
  285.     // port
  286.     a=strchr(adr,':');    // port
  287.     if (a) {
  288.       sscanf(a+1,"%d",&port);
  289.       strncat(_adr,adr,(int) a - (int) adr);
  290.     } else
  291.       strcpy(_adr,adr);
  292.     
  293.     // rΘcupΘrer adresse rΘsolue
  294.     strcpy(back->info,"host name");
  295.     hp = hts_gethostbyname(_adr);
  296.     if (hp == NULL) {
  297.       strcpy(back->r.msg,"Unable to get server's address");
  298.       back->status=FTP_STATUS_READY;    // fini
  299.       back->r.statuscode=-5;
  300.       _HALT_FTP
  301.         return 0;
  302.     }
  303.     _CHECK_HALT_FTP;
  304.     
  305.     // copie adresse
  306.     bcopy(hp->h_addr, (char *)&server.sin_addr, hp->h_length);
  307.     
  308.     // crΘer ("attachement") une socket (point d'accΦs) internet,en flot
  309.     soc_ctl=socket(AF_INET,SOCK_STREAM,0);
  310.     if (soc_ctl==INVALID_SOCKET) {
  311.       strcpy(back->r.msg,"Unable to create a socket");
  312.       back->status=FTP_STATUS_READY;    // fini
  313.       back->r.statuscode=-1;
  314.       _HALT_FTP
  315.         return 0;
  316.     }
  317.     server.sin_family = AF_INET;
  318.     server.sin_port = htons((unsigned short int) port);
  319.     
  320.     // connexion (bloquante, on est en thread)
  321.     strcpy(back->info,"connect");
  322.  
  323. #if HTS_WIN
  324.     if (connect(soc_ctl, (const struct sockaddr FAR *)&server, sizeof(server)) != 0) {
  325. #else
  326.       if (connect(soc_ctl, (struct sockaddr *)&server, sizeof(server)) == -1) {
  327. #endif
  328.         strcpy(back->r.msg,"Unable to connect to the server");
  329.         back->status=FTP_STATUS_READY;    // fini
  330.         back->r.statuscode=-1;
  331.         _HALT_FTP
  332.           return 0;
  333. #if HTS_WIN
  334.       }
  335. #else
  336.     }
  337. #endif
  338.     _CHECK_HALT_FTP;
  339.     
  340.     {
  341.       char line[1024];
  342.       // envoi du login
  343.       
  344.       // --USER--
  345.       get_line(soc_ctl,line,timeout);    // en tΩte
  346.       _CHECK_HALT_FTP;
  347.       
  348.       if (line[0]=='2') {        // ok, connectΘ
  349.         strcpy(back->info,"login: user");
  350.         sprintf(line,"USER %s",user);
  351.         send_line(soc_ctl,line);
  352.         get_line(soc_ctl,line,timeout);
  353.         _CHECK_HALT_FTP;      
  354.         if (line[0]=='3') {
  355.           // --PASS--
  356.           strcpy(back->info,"login: pass");
  357.           sprintf(line,"PASS %s",pass);
  358.           send_line(soc_ctl,line);
  359.           get_line(soc_ctl,line,timeout);
  360.           _CHECK_HALT_FTP;      
  361.           if (line[0]=='2') {  // ok
  362.             // --CWD--
  363.             char* a;
  364.             a=back->url_fil + strlen(back->url_fil)-1;
  365.             while( ((int) a > (int) back->url_fil) && (*a!='/')) a--;
  366.             if (*a == '/') {    // ok repΘrΘ
  367.               char target[1024];
  368.               target[0]='\0';
  369.               strncat(target,back->url_fil,(int) a - (int) back->url_fil);
  370.               if (strnotempty(target)==0)
  371.                 strcat(target,"/");
  372.               strcpy(back->info,"cwd");
  373.               sprintf(line,"CWD %s",target);
  374.               send_line(soc_ctl,line);
  375.               get_line(soc_ctl,line,timeout);
  376.               _CHECK_HALT_FTP;      
  377.               if (line[0]=='2') {
  378.                 send_line(soc_ctl,"TYPE I");
  379.                 get_line(soc_ctl,line,timeout);
  380.                 _CHECK_HALT_FTP;      
  381.                 if (line[0]=='2') {
  382.                   // ok..
  383.                 } else {
  384.                   strcpy(back->r.msg,"TYPE I error");
  385.                   back->status=FTP_STATUS_READY;    // fini
  386.                   back->r.statuscode=-1;
  387.                 }
  388.               } else {
  389.                 sprintf(back->r.msg,"CWD error: %s",linejmp(line));
  390.                 back->status=FTP_STATUS_READY;    // fini
  391.                 back->r.statuscode=-1;
  392.               }    // sinon on est prΩts
  393.             } else {
  394.               strcpy(back->r.msg,"Unexpected ftp error");
  395.               back->status=FTP_STATUS_READY;    // fini
  396.               back->r.statuscode=-1;
  397.             }
  398.             
  399.           } else {
  400.             sprintf(back->r.msg,"Bad password: %s",linejmp(line));
  401.             back->status=FTP_STATUS_READY;    // fini
  402.             back->r.statuscode=-1;
  403.           }
  404.         } else {
  405.           sprintf(back->r.msg,"Bad user name: %s",linejmp(line));
  406.           back->status=FTP_STATUS_READY;    // fini
  407.           back->r.statuscode=-1;
  408.         }
  409.       } else {
  410.         sprintf(back->r.msg,"Connection refused: %s",linejmp(line));
  411.         back->status=FTP_STATUS_READY;    // fini
  412.         back->r.statuscode=-1;
  413.       }
  414.      
  415.       // ok, si on est prΩts on Θcoute sur un port et on demande la sauce
  416.       if (back->r.statuscode != -1) {
  417.  
  418.         
  419.         //
  420.         // PrΘ-REST
  421.         //
  422. #if FTP_PASV
  423.         strcpy(back->info,"pasv");
  424.         sprintf(line,"PASV");
  425.         send_line(soc_ctl,line);
  426.         get_line(soc_ctl,line,timeout);
  427.         _CHECK_HALT_FTP;      
  428.         if (line[0]=='2') {
  429.           char *a,*b,*c;
  430.           a=strchr(line,'(');       // exemple: 227 Entering Passive Mode (123,45,67,89,177,27)
  431.           if (a) {
  432.            
  433.             // -- analyse de l'adresse IP et du port --
  434.             a++;
  435.             b=strchr(a,',');
  436.             if (b) b=strchr(b+1,',');
  437.             if (b) b=strchr(b+1,',');
  438.             if (b) b=strchr(b+1,',');
  439.             c=a; while( (c=strchr(c,',')) ) *c='.';        // remplacer , par .
  440.             if (b) *b='\0';
  441.             //
  442.             strcpy(adr_ip,a);       // copier adresse ip
  443.             //
  444.             if (b) {
  445.               a=b+1;  // dΘbut du port
  446.               b=strchr(a,'.');
  447.               if (b) {
  448.                 int n1,n2;
  449.                 //
  450.                 *b='\0';
  451.                 b++;
  452.                 c=strchr(b,')');
  453.                 if (c) {
  454.                   *c='\0';
  455.                   //
  456.                   if ( (sscanf(a,"%d",&n1)==1) && (sscanf(b,"%d",&n2)==1) && (strlen(adr_ip)<=16)) {
  457.                     //
  458. #ifndef HTS_LITTLE_ENDIAN
  459.                     port_pasv=n2+(n1<<8);
  460. #else
  461.                     port_pasv=n1+(n2<<8);
  462. #endif
  463.                   }
  464.                 } else {
  465.                   deletesoc(soc_dat); soc_dat=INVALID_SOCKET;
  466.                 }    // sinon on est prΩts
  467.               }
  468.             }
  469.             // -- fin analyse de l'adresse IP et du port --
  470.           } else {
  471.             sprintf(back->r.msg,"PASV incorrect: %s",linejmp(line));
  472.             back->status=FTP_STATUS_READY;    // fini
  473.             back->r.statuscode=-1;
  474.           }    // sinon on est prΩts
  475.         } else {
  476.           sprintf(back->r.msg,"PASV error: %s",linejmp(line));
  477.           back->status=FTP_STATUS_READY;    // fini
  478.           back->r.statuscode=-1;
  479.         }    // sinon on est prΩts
  480. #else
  481.         // rien α faire avant
  482. #endif
  483.  
  484. #if FTP_PASV
  485.         if (port_pasv) {
  486. #endif
  487.           // REST lui mΩme
  488.           if (back->r.statuscode != -1) {
  489.             if (!transfer_list) {
  490.               // SIZE?
  491.               strcpy(back->info,"size");
  492.               sprintf(line,"SIZE %s",ftp_filename);
  493.               send_line(soc_ctl,line);
  494.               get_line(soc_ctl,line,timeout);
  495.               _CHECK_HALT_FTP;      
  496.               if (line[0]=='2') {  // SIZE compris, ALORS tester REST (sinon pas tester: cf probleme des txt.gz decompresses a la volee)
  497.                 // REST?
  498.                 if (fexist(back->url_sav) && (transfer_list==0)) {
  499.                   strcpy(back->info,"rest");
  500.                   sprintf(line,"REST "LLintP,(LLint)fsize(back->url_sav));
  501.                   send_line(soc_ctl,line);
  502.                   get_line(soc_ctl,line,timeout);
  503.                   _CHECK_HALT_FTP;      
  504.                   if (line[0]=='3') {  // ok
  505.                     rest_understood=1;
  506.                   } // sinon tant pis 
  507.                 } 
  508.               }  // sinon tant pis 
  509.             }
  510.           }
  511. #if FTP_PASV
  512.         }
  513. #endif
  514.  
  515.         //
  516.         // Post-REST
  517.         //
  518. #if FTP_PASV
  519.         // Ok, se connecter
  520.         if (port_pasv) {
  521.           struct sockaddr_in server;
  522.           t_hostent* hp;    
  523.           // effacer structure
  524.           bzero((char *)&server, sizeof(server));
  525.           
  526.           // infos
  527.           strcpy(back->info,"resolv");
  528.           
  529.           // rΘsoudre
  530.           hp = hts_gethostbyname(adr_ip);
  531.           
  532.           // infos
  533.           strcpy(back->info,"cnxdata");
  534. #if FTP_DEBUG
  535.           printf("Data: Connecting to %s:%d...\n",adr_ip,port_pasv);
  536. #endif
  537.           if (hp) {
  538.             // copie adresse
  539.             bcopy(hp->h_addr, (char *)&server.sin_addr, hp->h_length);
  540.             
  541.             // socket
  542.             soc_dat=socket(AF_INET,SOCK_STREAM,0);
  543.             if (soc_dat != INVALID_SOCKET) {
  544.               // structure: connexion au domaine internet, port 80 (ou autre)
  545.               server.sin_family = AF_INET;
  546.               server.sin_port = htons((unsigned short int) port_pasv);
  547. #if HTS_WIN
  548.               if (connect(soc_dat, (const struct sockaddr FAR *)&server, sizeof(server)) == 0) {
  549. #else
  550.               if (connect(soc_dat, (struct sockaddr *)&server, sizeof(server)) != -1) {
  551. #endif
  552.                 strcpy(back->info,"retr");
  553.                 strcpy(line,line_retr);
  554.                 send_line(soc_ctl,line);
  555.                 get_line(soc_ctl,line,timeout);
  556.                 _CHECK_HALT_FTP;      
  557.                 if (line[0]=='1') {
  558.                   // OK
  559.                 } else {
  560.                   deletesoc(soc_dat); soc_dat=INVALID_SOCKET;
  561.                   //
  562.                   sprintf(back->r.msg,"RETR command errror: %s",linejmp(line));
  563.                   back->status=FTP_STATUS_READY;    // fini
  564.                   back->r.statuscode=-1;
  565.                 }    // sinon on est prΩts
  566.               } else {
  567.                 deletesoc(soc_dat); soc_dat=INVALID_SOCKET;
  568.                 //
  569.                 strcpy(back->r.msg,"Unable to connect");
  570.                 back->status=FTP_STATUS_READY;    // fini
  571.                 back->r.statuscode=-1;
  572.               }    // sinon on est prΩts
  573.             } else {
  574.               strcpy(back->r.msg,"Unable to create a socket");
  575.               back->status=FTP_STATUS_READY;    // fini
  576.               back->r.statuscode=-1;
  577.             }    // sinon on est prΩts
  578.           } else {
  579.             sprintf(back->r.msg,"Unable to resolve IP %s",adr_ip);
  580.             back->status=FTP_STATUS_READY;    // fini
  581.             back->r.statuscode=-1;
  582.           }    // sinon on est prΩts
  583.         } else {
  584.           sprintf(back->r.msg,"PASV incorrect: %s",linejmp(line));
  585.           back->status=FTP_STATUS_READY;    // fini
  586.           back->r.statuscode=-1;
  587.         }    // sinon on est prΩts
  588. #else
  589.         //T_SOC soc_servdat;
  590.         strcpy(back->info,"listening");
  591.         if ( (soc_servdat = get_datasocket(line)) != INVALID_SOCKET) {
  592.           _CHECK_HALT_FTP;      
  593.           send_line(soc_ctl,line);          // envoi du RETR
  594.           get_line(soc_ctl,line,timeout);
  595.           _CHECK_HALT_FTP;      
  596.           if (line[0]=='2') {  // ok
  597.             strcpy(back->info,"retr");
  598.             strcpy(line,line_retr);
  599.             send_line(soc_ctl,line);
  600.             get_line(soc_ctl,line,timeout);
  601.             _CHECK_HALT_FTP;      
  602.             if (line[0]=='1') {
  603.               //T_SOC soc_dat;
  604.               struct sockaddr dummyaddr;
  605.               int dummylen = sizeof(struct sockaddr);
  606.               if ( (soc_dat=accept(soc_servdat,&dummyaddr,&dummylen)) == INVALID_SOCKET) {
  607.                 strcpy(back->r.msg,"Unable to accept connection");
  608.                 back->status=FTP_STATUS_READY;    // fini
  609.                 back->r.statuscode=-1;
  610.               }
  611.             } else {
  612.               sprintf(back->r.msg,"RETR command errror: %s",linejmp(line));
  613.               back->status=FTP_STATUS_READY;    // fini
  614.               back->r.statuscode=-1;
  615.             }
  616.           } else {
  617.             sprintf(back->r.msg,"PORT command error: %s",linejmp(line));
  618.             back->status=FTP_STATUS_READY;    // fini
  619.             back->r.statuscode=-1;
  620.           }
  621. #if HTS_WIN
  622.           closesocket(soc_servdat);
  623. #else
  624.           close(soc_servdat);
  625. #endif
  626.         } else {
  627.           strcpy(back->r.msg,"Unable to listen to a port");
  628.           back->status=FTP_STATUS_READY;    // fini
  629.           back->r.statuscode=-1;
  630.         }
  631. #endif
  632.         
  633.         //
  634.         // Ok, connexion initiΘe
  635.         //
  636.         if (soc_dat != INVALID_SOCKET) {
  637.           if (rest_understood) {         // REST envoyΘe et comprise
  638.             filenote(back->url_sav,NULL);
  639.             back->r.fp = fopen(fconv(back->url_sav),"ab");
  640.           } else
  641.             back->r.fp = filecreate(back->url_sav);
  642.           strcpy(back->info,"receiving");
  643.           if (back->r.fp != NULL) {
  644.             char buff[1024];
  645.             int len=1;
  646.             int read_len=1024;
  647.             HTS_TOTAL_RECV_CHECK(read_len);         // Diminuer au besoin si trop de donnΘes reτues
  648.             
  649.             while( (len>0) && (!stop_ftp(back)) ) {
  650.               // attendre les donnΘes
  651.               len=1;    // pas d'erreur pour le moment
  652.               switch(wait_socket_receive(soc_dat,timeout)) {
  653.               case -1:
  654.                 strcpy(back->r.msg,"Read error");
  655.                 back->status=FTP_STATUS_READY;    // fini
  656.                 back->r.statuscode=-1;
  657.                 len=0;    // fin
  658.                 break;
  659.               case 0:
  660.                 sprintf(back->r.msg,"Time out (%d)",timeout);
  661.                 back->status=FTP_STATUS_READY;    // fini
  662.                 back->r.statuscode=-1;
  663.                 len=0;    // fin
  664.                 break;
  665.               }
  666.               
  667.               // rΘception
  668.               if (len) {
  669.                 len=recv(soc_dat,buff,read_len,0);
  670.                 if (len>0) {
  671.                   back->r.size+=len;
  672.                   HTS_STAT.HTS_TOTAL_RECV+=len; 
  673.                   if (back->r.fp) {
  674.                     if ((int) fwrite(buff,1,len,back->r.fp) != len) {
  675.                       strcpy(back->r.msg,"Write error");
  676.                       back->status=FTP_STATUS_READY;    // fini
  677.                       back->r.statuscode=-1;
  678.                       len=0;  // error
  679.                     }
  680.                   } else {
  681.                     strcpy(back->r.msg,"Unexpected write error");
  682.                     back->status=FTP_STATUS_READY;    // fini
  683.                     back->r.statuscode=-1;
  684.                   }
  685.                 } else {        // Erreur ou terminΘ
  686.                   //strcpy(back->r.msg,"Read error");
  687.                   back->status=FTP_STATUS_READY;    // fini
  688.                   back->r.statuscode=0;
  689.                 }
  690.                 read_len=1024; HTS_TOTAL_RECV_CHECK(read_len);         // Diminuer au besoin si trop de donnΘes reτues
  691.               }
  692.             }
  693.             if (back->r.fp) { 
  694.               fclose(back->r.fp); 
  695.               back->r.fp=NULL;
  696.             }
  697.           } else {
  698.             strcpy(back->r.msg,"Unable to write file");
  699.             back->status=FTP_STATUS_READY;    // fini
  700.             back->r.statuscode=-1;
  701.           }
  702. #if HTS_WIN
  703.           closesocket(soc_dat);
  704. #else
  705.           close(soc_dat);
  706. #endif
  707.           
  708.           // 226 Transfer complete?
  709.           if (back->r.statuscode != -1) {
  710.             if (wait_socket_receive(soc_ctl,timeout_onfly)>0) {
  711.               // rΘcupΘrer 226 transfer complete
  712.               get_line(soc_ctl,line,timeout);
  713.               if (line[0]=='2') {       // OK
  714.                 strcpy(back->r.msg,"OK");
  715.                 back->status=FTP_STATUS_READY;    // fini
  716.                 back->r.statuscode=200;
  717.               } else {
  718.                 sprintf(back->r.msg,"RETR incorrect: %s",linejmp(line));
  719.                 back->status=FTP_STATUS_READY;    // fini
  720.                 back->r.statuscode=-1;
  721.               }
  722.             } else {
  723.               strcpy(back->r.msg,"Read error");
  724.               back->status=FTP_STATUS_READY;    // fini
  725.               back->r.statuscode=-1;
  726.             }
  727.           }
  728.           
  729.         }
  730.         
  731.         
  732.         
  733.       }
  734.       
  735.       
  736.     }
  737.     
  738.     _CHECK_HALT_FTP;
  739.     strcpy(back->info,"quit");
  740.     send_line(soc_ctl,"QUIT");    // bye bye
  741.     get_line(soc_ctl,NULL,timeout);
  742. #if HTS_WIN
  743.     closesocket(soc_ctl);
  744. #else
  745.     close(soc_ctl);
  746. #endif
  747.   }
  748.   
  749.   if (back->r.statuscode!=-1) {
  750.     back->r.statuscode=200;
  751.     strcpy(back->r.msg,"OK");
  752.   }
  753.   back->status=FTP_STATUS_READY;    // fini
  754.   return 0;
  755. }
  756.  
  757.  
  758.  
  759. // ouverture d'un port
  760. T_SOC get_datasocket(char* to_send) {
  761.   T_SOC soc = INVALID_SOCKET;
  762.   char h_loc[256+2];
  763.   
  764.   to_send[0]='\0';
  765.   if (gethostname(h_loc,256)==0) {    // host name
  766.     t_hostent* hp_loc;    
  767.     if ( (hp_loc=gethostbyname(h_loc)) ) {  // notre host      
  768.       if ( (soc=socket(AF_INET,SOCK_STREAM,0)) != INVALID_SOCKET) {
  769.         struct sockaddr_in server;
  770.         // effacer structure
  771.         bzero((char *)&server, sizeof(server));
  772.         server.sin_family = AF_INET;
  773.         server.sin_port = htons((unsigned short int) 0);    // demander port qque
  774.         // copie adresse locale
  775.         bcopy(hp_loc->h_addr, (char *)&server.sin_addr, hp_loc->h_length);
  776.         // // NAAN server.sin_addr.s_addr=htonl(INADDR_ANY);
  777.         if ( bind(soc,(struct sockaddr*) &server,sizeof(struct sockaddr)) == 0 ) {
  778.           struct sockaddr_in server2;
  779.           int len;
  780.           len=sizeof(server2);
  781.           // effacer structure
  782.           bzero((char *)&server2, sizeof(server2));
  783.           if (getsockname(soc,(struct sockaddr*) &server2,&len) == 0) {
  784.             // *port=ntohs(server.sin_port);  // rΘcupΘrer port
  785.             if (listen(soc,10)>=0) {    // au pif le 10
  786.               unsigned short int a,n1,n2;
  787.               // calculer port
  788.               a  = server2.sin_port;
  789. #ifndef HTS_LITTLE_ENDIAN
  790.               n1 = (a & 0xff);
  791.               n2 = ((a>>8) & 0xff);
  792. #else
  793.               n2 = (a & 0xff);
  794.               n1 = ((a>>8) & 0xff);
  795. #endif
  796.               // calculer adresse
  797.               // pour commande port
  798.               {
  799.                 char dots[256];
  800.                 char* a;
  801.                 char* dot = (char*) inet_ntoa(server2.sin_addr);
  802.                 dots[0]='\0';
  803.                 //
  804.                 strncat(dots,dot,32);
  805.                 while( (a=strchr(dots,'.')) ) *a=',';    // virgules!
  806.                 sprintf(to_send,"PORT %s,%d,%d",dots,n1,n2);  
  807.               }
  808.               
  809.             } else {
  810. #if HTS_WIN
  811.               closesocket(soc);
  812. #else
  813.               close(soc);
  814. #endif
  815.               soc=INVALID_SOCKET;
  816.             }
  817.             
  818.             
  819.           } else {
  820. #if HTS_WIN
  821.             closesocket(soc);
  822. #else
  823.             close(soc);
  824. #endif
  825.             soc=INVALID_SOCKET;
  826.           }
  827.           
  828.           
  829.         } else {
  830. #if HTS_WIN
  831.           closesocket(soc);
  832. #else
  833.           close(soc);
  834. #endif
  835.           soc=INVALID_SOCKET;
  836.         }
  837.       }
  838.     }
  839.   }
  840.   
  841.   
  842.   return soc;
  843. }
  844.  
  845. #if FTP_DEBUG
  846. FILE* dd=NULL;
  847. #endif
  848.  
  849. // routines de rΘception/Θmission
  850. // 0 = ERROR
  851. int send_line(T_SOC soc,char* data) {
  852.   char line[1024];
  853.   if (_DEBUG_HEAD) {
  854.     if (ioinfo) {
  855.       fprintf(ioinfo,"---> %s\x0d\x0a",data);
  856.       fflush(ioinfo);
  857.     }
  858.   }
  859. #if FTP_DEBUG
  860.   if (dd == NULL) dd = fopen("toto.txt","w");
  861.   fprintf(dd,"---> %s\x0d\x0a",data); fflush(dd);
  862.   printf("---> %s",data); fflush(stdout);
  863. #endif
  864.   sprintf(line,"%s\x0d\x0a",data);
  865.   if (check_socket_connect(soc) != 1) {
  866. #if FTP_DEBUG
  867.     printf("!SOC WRITE ERROR\n");
  868. #endif
  869.     return 0;    // erreur, plus connectΘ!
  870.   }
  871. #if FTP_DEBUG
  872.   {
  873.     int r = (send(soc,line,strlen(line),0) == (int) strlen(line));
  874.     printf("%s\x0d\x0a",data); fflush(stdout);
  875.     return r;
  876.   }
  877. #else
  878.   return (send(soc,line,strlen(line),0) == (int) strlen(line));
  879. #endif
  880. }
  881.  
  882. int get_line(T_SOC soc,char* line,int timeout) {
  883.   char data[1024];
  884.   int i,ok;
  885. #if FTP_DEBUG
  886.   if (dd == NULL) dd = fopen("toto.txt","w");
  887. #endif
  888.   
  889.   data[0]='\0';
  890.   i=0; ok=0; data[3]='\0';
  891.   do {
  892.     char b;                        
  893.     int dummy=1;    // =1 : dummy (pour CHECK)
  894.     
  895.     // vΘrifier donnΘes
  896.     switch(wait_socket_receive(soc,timeout)) {
  897.     case -1:   // erreur de lecture
  898.       if (line) strcpy(line,"500 *read error");
  899.       return 0;
  900.       break;
  901.     case 0:
  902.       if (line) sprintf(line,"500 *read timeout (%d)",timeout);
  903.       return 0;
  904.       break;
  905.     }
  906.     
  907.     HTS_TOTAL_RECV_CHECK(dummy);     // Diminuer au besoin si trop de donnΘes reτues
  908.     switch(recv(soc,&b,1,0)) {
  909.       //case 0: break;    // pas encore --> erreur (on attend)!
  910.     case 1:
  911.       HTS_STAT.HTS_TOTAL_RECV+=1; // compter flux entrant
  912.       if ((b!=10) && (b!=13))
  913.         data[i++]=b;
  914.       break;
  915.     default:
  916.       if (line) strcpy(line,"500 *read error");
  917.       return 0; // error
  918.       break;
  919.     }
  920.     if ( ((b==13) || (b==10)) && (i>0) ){    // CR/LF
  921.       if (data[3]!='-')          // y'en a encore!!
  922.         ok=1;    // sortir
  923.       else {  // suivante
  924.         data[3]='\0';
  925.         i=0;
  926.       }
  927.     }
  928.   } while(!ok);
  929.   data[i++]='\0';
  930.   
  931.   if (_DEBUG_HEAD) {
  932.     if (ioinfo) {
  933.       fprintf(ioinfo,"<--- %s\x0d\x0a",data);
  934.       fflush(ioinfo);
  935.     }
  936.   }
  937. #if FTP_DEBUG
  938.   fprintf(dd,"<--- %s\n",data); fflush(dd);
  939.   printf("<--- %s\n",data);
  940. #endif
  941.   if (line) strcpy(line,data);
  942.   return (strnotempty(data));
  943. }
  944.  
  945. // sauter NNN
  946. char* linejmp(char* line) {
  947.   if (strlen(line)>4)
  948.     return line+4;
  949.   else
  950.     return line;
  951. }
  952.  
  953. // test socket:
  954. // 0 : no data
  955. // 1 : data detected
  956. // -1: error
  957. int check_socket(T_SOC soc) {
  958.   fd_set fds,fds_e;           // poll structures
  959.   struct timeval tv;          // structure for select
  960.   FD_ZERO(&fds);
  961.   FD_ZERO(&fds_e); 
  962.   // socket read 
  963.   FD_SET(soc,&fds);           
  964.   // socket error
  965.   FD_SET(soc,&fds_e);
  966.   tv.tv_sec=0;
  967.   tv.tv_usec=0;
  968.   // poll!     
  969.   select(soc + 1,&fds,NULL,&fds_e,&tv);
  970.   if (FD_ISSET(soc,&fds_e)) {  // error detected
  971.     return -1;
  972.   } else if (FD_ISSET(soc,&fds)) {
  973.     return 1;
  974.   }
  975.   return 0;
  976. }
  977. // check if connected
  978. int check_socket_connect(T_SOC soc) {
  979.   fd_set fds,fds_e;           // poll structures
  980.   struct timeval tv;          // structure for select
  981.   FD_ZERO(&fds);
  982.   FD_ZERO(&fds_e); 
  983.   // socket write 
  984.   FD_SET(soc,&fds);           
  985.   // socket error
  986.   FD_SET(soc,&fds_e);
  987.   tv.tv_sec=0;
  988.   tv.tv_usec=0;
  989.   // poll!     
  990.   select(soc + 1,NULL,&fds,&fds_e,&tv);
  991.   if (FD_ISSET(soc,&fds_e)) {  // error detected
  992.     return -1;
  993.   } else if (FD_ISSET(soc,&fds)) {
  994.     return 1;
  995.   }
  996.   return 0;
  997. }
  998. // attendre des donnΘes
  999. int wait_socket_receive(T_SOC soc,int timeout) {
  1000.   // attendre les donnΘes
  1001.   double ltime=time_local();
  1002.   int r;
  1003. #if FTP_DEBUG
  1004.   printf("\x0dWaiting for data "); fflush(stdout);
  1005. #endif
  1006.   while( (!(r = check_socket(soc))) && ( ((int) ((double) (time_local()-ltime))) < timeout )) {
  1007.     Sleep(100);
  1008. #if FTP_DEBUG
  1009.     printf("."); fflush(stdout);
  1010. #endif
  1011.   }
  1012. #if FTP_DEBUG
  1013.   printf("\x0dreturn: %d\x0d",r); fflush(stdout);
  1014. #endif
  1015.   return r;
  1016. }
  1017.  
  1018.  
  1019. // cancel reτu?
  1020. int stop_ftp(lien_back* back) {
  1021.   if (back->stop_ftp) {
  1022.     strcpy(back->r.msg,"Cancelled by User");
  1023.     back->status=FTP_STATUS_READY;    // fini
  1024.     back->r.statuscode=-1;
  1025.     return 1;
  1026.   }
  1027.   return 0;
  1028. }
  1029.  
  1030.  
  1031.  
  1032.  
  1033.